home *** CD-ROM | disk | FTP | other *** search
/ Amiga Magazin: Amiga-CD 1997 May & June / Amiga-CD 1997 #5-6.iso / emulatoren / frodov2.4 / src / display.c < prev    next >
C/C++ Source or Header  |  1997-01-03  |  18KB  |  769 lines

  1. /*
  2.  *  Display.c - Darstellung der C64-Grafik,
  3.  *              Handhabung des Emulatorfensters
  4.  *
  5.  *  Copyright (C) 1994-1996 by Christian Bauer
  6.  */
  7.  
  8. /*
  9.  *  Anmerkungen:
  10.  *  ------------
  11.  *
  12.  *  - Die Farbpalette besteht aus den 16 C64-Farben, 16mal wiederholt.
  13.  *    Dadurch spart man sich das Ausmaskieren der unteren 4 Bit bei den
  14.  *    VIC-Farbcodes. Allerdings muß dieses bei der Chunky->Planar-
  15.  *    Konvertierung für die Amiga-Chips erfolgen (der Algorithmus
  16.  *    setzt voraus, daß die oberen Nibbles Null sind).
  17.  */
  18.  
  19. #include <exec/types.h>
  20. #include <exec/libraries.h>
  21. #include <exec/memory.h>
  22. #include <intuition/intuition.h>
  23. #include <intuition/screens.h>
  24. #include <graphics/copper.h>
  25. #include <graphics/gfxmacros.h>
  26. #include <hardware/custom.h>
  27. #include <libraries/gadtools.h>
  28. #include <devices/timer.h>
  29. #include <clib/exec_protos.h>
  30. #include <clib/intuition_protos.h>
  31. #include <clib/graphics_protos.h>
  32. #include <clib/gadtools_protos.h>
  33. #include <clib/timer_protos.h>
  34. #include <string.h>
  35.  
  36. #include "Display.h"
  37. #include "SAM.h"
  38. #include "Prefs.h"
  39. #define CATCOMP_NUMBERS 1
  40. #include "LocStrings.h"
  41.  
  42.  
  43. // Aus Main.asm
  44. extern struct Library *GfxBase;
  45. extern struct Library *IntuitionBase;
  46. extern void ShowPrefs(void);
  47. extern void PutChProc(void);
  48. extern char *GetStr(int strnum);
  49. extern void ResetC64(void);
  50.  
  51. // Aus 6510.asm
  52. extern struct Task *CPUTask;
  53. extern void Pause6510(void);
  54. extern void Resume6510(void);
  55. extern ULONG InvokeSAMSet;
  56.  
  57. // Aus 6526.asm
  58. extern void KeyPressed(char c);
  59. extern WORD JoystickSwap;
  60.  
  61. // Aus 6569.asm
  62. extern APTR CURRENTA5;
  63. extern BYTE ChunkyBuf[];
  64. extern UWORD SkipLatch;
  65. extern UWORD LimitSpeed;
  66. extern void graffiti_conv(UBYTE *p0, UBYTE *p1, UBYTE *p2, UBYTE *p3);
  67.  
  68. // Aus 6581.asm
  69. extern void PauseSound(void);
  70. extern void ResumeSound(void);
  71.  
  72. // Aus c2p4.asm
  73. extern void c2p4(UBYTE *fBUFFER, UBYTE *fBUFFER_CMP, APTR *planes, struct Task *task, ULONG signals);
  74. extern int Initc2p4(void);
  75. extern void Exitc2p4(void);
  76.  
  77.  
  78. // Prototypes
  79. void open_double_buf(int type, int width, int height);
  80. void set_graffiti_commands(void);
  81. int handle_IDCMP(int done);
  82. int handle_menu(int menu, int item, int done);
  83.  
  84.  
  85. char has_gfx_39, has_gfx_40;  // Flags für Version der graphics.library
  86.  
  87. int current_type, current_width, current_height;
  88.  
  89. struct Screen *the_screen;
  90. struct Window *the_window;
  91. struct VisualInfo *the_visual_info;
  92. struct RastPort *the_rast_port;
  93. struct ViewPort *the_view_port;
  94. struct TextFont *topaz_font;
  95. struct Menu *the_menus;
  96.  
  97. // Für WritePixelArray8()
  98. struct BitMap *temp_bm;
  99. struct BitMap v37_temp_bm;
  100. struct RastPort temp_rp;
  101.  
  102. // Double Buffering
  103. struct ScreenBuffer *scr_buf[2];
  104. int inv_buf_num;
  105. char using_db;                // Flag: Double Buffering wird benutzt
  106.  
  107. // c2p4
  108. APTR comparison_buf[2];
  109. char c2p4_signal;            // Signal: c2p4 fertig
  110. LONGBITS c2p4_set;
  111. char must_wait_for_c2p4;    // Flag: Auf c2p4 muß gewartet werden
  112.  
  113. // Für Graffiti
  114. struct UCopList *the_ucoplist;
  115. extern struct Custom custom;
  116. const UBYTE graffiti_pal_red[16] = {
  117.   0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8
  118. };
  119. const UBYTE graffiti_pal_green[16] = {
  120.   0, 0, 0, 0, 8, 8, 8, 8, 0, 0, 0, 0, 8, 8, 8, 8
  121. };
  122. const UBYTE graffiti_pal_blue[16] = {
  123.   0, 1, 8, 9, 0, 1, 8, 9, 0, 1, 8, 9, 0, 1, 8, 9
  124. };
  125.  
  126. // Geschwindigkeitsanzeige
  127. struct MsgPort *timer_port;
  128. struct timerequest *timer_io;
  129.  
  130.  
  131. const struct TextAttr topaz_attr = {
  132.   "topaz.font", 8, FS_NORMAL, 0
  133. };
  134.  
  135. struct NewMenu new_menus[] = {
  136.   NM_TITLE, MSG_EMULATION_MENU, NULL, 0, 0, NULL,
  137.   NM_ITEM, MSG_SETTINGS_MENU, "P", 0, 0, NULL,
  138.   NM_ITEM, MSG_SAM_MENU, "M", 0, 0, NULL,
  139.   NM_ITEM, NM_BARLABEL, NULL, 0, 0, NULL,
  140.   NM_ITEM, MSG_QUIT_MENU, "Q", 0, 0, NULL,
  141.   NM_END, NULL, NULL, 0, 0, NULL
  142. };
  143.  
  144. const UBYTE palette_red[16] = {
  145.   0, 15, 12, 0, 15, 0, 0, 15, 15, 8, 15, 4, 8, 8, 8, 12
  146. };
  147.  
  148. const UBYTE palette_green[16] = {
  149.   0, 15, 0, 15, 0, 12, 0, 15, 8, 4, 8, 4, 8, 15, 8, 12
  150. };
  151.  
  152. const UBYTE palette_blue[16] = {
  153.   0, 15, 0, 12, 15, 0, 12, 0, 0, 0, 8, 4, 8, 8, 15, 12
  154. };
  155.  
  156.  
  157. /*
  158.  *  Screen und Fenster öffnen, alles vorbereiten
  159.  *  0: OK, 1: Fehler beim Screen-Öffnen, 2: Kein Speicher
  160.  */
  161.  
  162. int OpenDisplay(int type, ULONG display_id, UWORD overscan, int width, int height)
  163. {
  164.   int depth;
  165.   int i;
  166.  
  167.   has_gfx_39 = (GfxBase->lib_Version >= 39);
  168.   has_gfx_40 = (GfxBase->lib_Version >= 40);
  169.  
  170.   must_wait_for_c2p4 = FALSE;
  171.   using_db = FALSE;
  172.  
  173.   current_type = type;
  174.   current_width = width;
  175.   current_height = height;
  176.  
  177.   switch (type) {
  178.     case SCRTYPE_8BIT: depth = 8; break;
  179.     case SCRTYPE_4BIT: depth = 4; break;
  180.     case SCRTYPE_1BIT: depth = 1; break;
  181.     case SCRTYPE_GRAF:
  182.       depth = 4;
  183.       current_width = width = 640; current_height = height = 256;
  184.       display_id = PAL_MONITOR_ID | HIRES_KEY;
  185.       overscan = OSCAN_STANDARD;
  186.       break;
  187.   }
  188.  
  189.   if (!(the_screen = OpenScreenTags(NULL,
  190.     SA_Width, width,
  191.     SA_Height, height,
  192.     SA_DisplayID, display_id,
  193.     SA_Overscan, overscan,
  194.     SA_Depth, depth,
  195.     SA_Quiet, TRUE,
  196.     SA_AutoScroll, TRUE,
  197.     TAG_DONE)))
  198.     return 1;
  199.  
  200.   the_rast_port = &the_screen->RastPort;
  201.   the_view_port = &the_screen->ViewPort;
  202.  
  203.   if (topaz_font = OpenFont(&topaz_attr))
  204.     SetFont(the_rast_port, topaz_font);
  205.   SetAPen(the_rast_port, 1);
  206.  
  207.   if (!(the_visual_info = GetVisualInfo(the_screen, NULL)))
  208.     return 2;
  209.  
  210.   if (!(the_menus = CreateMenus(new_menus, GTMN_FullMenu, TRUE, TAG_DONE)))
  211.     return 2;
  212.   LayoutMenus(the_menus, the_visual_info, GTMN_NewLookMenus, TRUE, TAG_DONE);
  213.  
  214.   if (!(the_window = OpenWindowTags(NULL,
  215.     WA_Left, 0,
  216.     WA_Top, 0,
  217.     WA_Width, width,
  218.     WA_Height, height,
  219.     WA_CustomScreen, the_screen,
  220.     WA_IDCMP, IDCMP_RAWKEY | IDCMP_MENUPICK | IDCMP_MENUVERIFY,
  221.     WA_Backdrop, TRUE,
  222.     WA_Borderless, TRUE,
  223.     WA_NoCareRefresh, TRUE,
  224.     WA_Activate, TRUE,
  225.     WA_NewLookMenus, TRUE,
  226.     TAG_DONE)))
  227.     return 2;
  228.  
  229.   SetMenuStrip(the_window, the_menus);
  230.  
  231.   switch (type) {
  232.     case SCRTYPE_8BIT:
  233.  
  234.       // Farbpalette laden
  235.       for (i=0; i<256; i++)
  236.         SetRGB4(the_view_port, i,
  237.           palette_red[i & 0xf], palette_green[i & 0xf], palette_blue[i & 0xf]);
  238.  
  239.       // Temporären RastPort für WritePixelArray8() anlegen
  240.       if (has_gfx_39) {
  241.         if (!(temp_bm = AllocBitMap(width, 1, 8, 0, NULL)))
  242.           return 2;
  243.       } else {
  244.         InitBitMap(temp_bm = &v37_temp_bm, depth, width, 1);
  245.         for (i=0; i<8; i++)
  246.           if (!(v37_temp_bm.Planes[i] = AllocRaster(width, 1)))
  247.             return 2;
  248.       }
  249.  
  250.       InitRastPort(&temp_rp);
  251.       temp_rp.BitMap = temp_bm;
  252.  
  253.       CURRENTA5 = ChunkyBuf;  // Wird nicht mehr verändert
  254.       break;
  255.  
  256.     case SCRTYPE_4BIT:
  257.  
  258.       if (!Initc2p4())
  259.         return 2;
  260.  
  261.       // Speicher für Comparison Buffer holen
  262.       if (!(comparison_buf[0] = AllocVec(width * height, MEMF_PUBLIC | MEMF_CLEAR)))
  263.         return 2;
  264.  
  265.       // Farbpalette laden
  266.       for (i=0; i<16; i++)
  267.         SetRGB4(the_view_port, i,
  268.           palette_red[i & 0xf], palette_green[i & 0xf], palette_blue[i & 0xf]);
  269.  
  270.       CURRENTA5 = ChunkyBuf;
  271.  
  272.       open_double_buf(type, width, height);
  273.       must_wait_for_c2p4 = FALSE;
  274.       break;
  275.  
  276.     case SCRTYPE_1BIT:
  277.  
  278.       SetRGB4(the_view_port, 0, 0, 0, 0);        // schwarz
  279.       SetRGB4(the_view_port, 1, 15, 15, 15);    // weiß
  280.  
  281.       CURRENTA5 = the_rast_port->BitMap->Planes[0];
  282.  
  283.       open_double_buf(type, width, height);
  284.       break;
  285.  
  286.     case SCRTYPE_GRAF:
  287.  
  288.       // Interne Farbpalette laden
  289.       for (i=0; i<16; i++)
  290.         SetRGB4(the_view_port, i,
  291.           graffiti_pal_red[i], graffiti_pal_green[i], graffiti_pal_blue[i]);
  292.  
  293.       // Graffiti-Befehlssequenz erstellen und externe Farbpalette laden
  294.       set_graffiti_commands();
  295.  
  296.       // Copperliste installieren
  297.       if (!(the_ucoplist = (struct UCopList *)AllocVec(sizeof(struct UCopList), MEMF_PUBLIC | MEMF_CLEAR)))
  298.         return 2;
  299.  
  300.       CINIT(the_ucoplist, 0x258);
  301.       for (i=0; i<0x32; i++) {
  302.         CWAIT(the_ucoplist, i, 15);
  303.         CMOVE(the_ucoplist, custom.bplcon0, 0xc301);    // Hires, 4 Bitplanes, Genlock Audio
  304.       }
  305.       CEND(the_ucoplist);
  306.  
  307.       Forbid();
  308.       the_view_port->UCopIns = the_ucoplist;
  309.       Permit();
  310.       RethinkDisplay();
  311.  
  312.       CURRENTA5 = ChunkyBuf;
  313.       break;
  314.   }
  315.  
  316.   return 0;
  317. }
  318.  
  319.  
  320. /*
  321.  *  Erste Bildschirmzeile mit Graffiti-Kommandos beschreiben
  322.  */
  323.  
  324. void set_graffiti_commands(void)
  325. {
  326.   int i;
  327.   UBYTE *p0 = the_rast_port->BitMap->Planes[0];
  328.   UBYTE *p1 = the_rast_port->BitMap->Planes[1];
  329.   UBYTE *p2 = the_rast_port->BitMap->Planes[2];
  330.   UBYTE *p3 = the_rast_port->BitMap->Planes[3];
  331.  
  332.   *p0++ = 5;    // Pixel Read Mask = 15
  333.   *p1++ = 15;
  334.   *p2++ = 0;
  335.   *p3++ = 0;
  336.  
  337.   for (i=0; i<16; i++) {
  338.     *p0++ = 4;    // Set Color
  339.     *p1++ = i;
  340.     *p2++ = 6;    // Set RGB Value
  341.     *p3++ = palette_red[i] << 2;
  342.     *p0++ = 6;
  343.     *p1++ = palette_green[i] << 2;
  344.     *p2++ = 6;
  345.     *p3++ = palette_blue[i] << 2;
  346.   }
  347.  
  348.   for (i=0; i<80-32-2; i++) {
  349.     *p0++ = 0;    // NOP
  350.     *p1++ = 0;
  351.     *p2++ = 0;
  352.     *p3++ = 0;
  353.   }
  354.  
  355.   *p0++ = 0;    // NOP
  356.   *p1++ = 0;
  357.   *p2++ = 8;    // Start Lores
  358.   *p3++ = 0;
  359. }
  360.  
  361.  
  362. /*
  363.  *  Double Buffering einrichten
  364.  */
  365.  
  366. void open_double_buf(int type, int width, int height)
  367. {
  368.   using_db = FALSE;
  369.   if (IntuitionBase->lib_Version >= 39) {
  370.  
  371.     if (!(scr_buf[0] = AllocScreenBuffer(the_screen, NULL, SB_SCREEN_BITMAP)))
  372.       return;
  373.  
  374.     if (!(scr_buf[1] = AllocScreenBuffer(the_screen, NULL, SB_COPY_BITMAP)))
  375.       return;
  376.  
  377.     WaitTOF(); WaitTOF();
  378.     inv_buf_num = 1;
  379.  
  380.     if (type == SCRTYPE_4BIT) {
  381.       CURRENTA5 = ChunkyBuf;
  382.       if (!(comparison_buf[1] = AllocVec(width * height, MEMF_PUBLIC | MEMF_CLEAR)))
  383.         return;
  384.     } else {
  385.       CURRENTA5 = scr_buf[1]->sb_BitMap->Planes[0];
  386.     }
  387.  
  388.     using_db = TRUE;
  389.   }
  390. }
  391.  
  392.  
  393. /*
  394.  *  Screen und Fenster schließen
  395.  */
  396.  
  397. void CloseDisplay(void)
  398. {
  399.   int i;
  400.  
  401.   if (current_type == SCRTYPE_4BIT)
  402.     Exitc2p4();
  403.  
  404.   if (comparison_buf[0]) {
  405.     FreeVec(comparison_buf[0]);
  406.     comparison_buf[0] = NULL;
  407.   }
  408.  
  409.   if (comparison_buf[1]) {
  410.     FreeVec(comparison_buf[1]);
  411.     comparison_buf[1] = NULL;
  412.   }
  413.  
  414.   if (IntuitionBase->lib_Version >= 39) {
  415.     FreeScreenBuffer(the_screen, scr_buf[0]);  // NULL ist OK
  416.     scr_buf[0] = NULL;
  417.     FreeScreenBuffer(the_screen, scr_buf[1]);
  418.     scr_buf[1] = NULL;
  419.   }
  420.  
  421.   if (the_menus) {
  422.     ClearMenuStrip(the_window);
  423.     FreeMenus(the_menus);
  424.     the_menus = NULL;
  425.   }
  426.  
  427.   if (the_window) {
  428.     CloseWindow(the_window);
  429.     the_window = NULL;
  430.   }
  431.  
  432.   // Temporären RastPort schließen
  433.   if (temp_bm) {
  434.     if (has_gfx_39)
  435.       FreeBitMap(temp_bm);
  436.     else {
  437.       for (i=0; i<8; i++) {
  438.         FreeRaster(v37_temp_bm.Planes[i], current_width, current_height);
  439.         v37_temp_bm.Planes[i] = NULL;
  440.       }
  441.     }
  442.     temp_bm = NULL;
  443.   }
  444.  
  445.   if (the_visual_info) {
  446.     FreeVisualInfo(the_visual_info);
  447.     the_visual_info = NULL;
  448.   }
  449.  
  450.   if (topaz_font) {
  451.     CloseFont(topaz_font);
  452.     topaz_font = NULL;
  453.   }
  454.  
  455.   if (the_screen) {
  456.     CloseScreen(the_screen);
  457.     the_screen = NULL;
  458.   }
  459. }
  460.  
  461.  
  462. /*
  463.  *  Vom 6510-Task aus nötige Initialisierungen
  464.  *  Wird vom 6510-Task aufgerufen
  465.  */
  466.  
  467. void InitDisplayFrom6510(void)
  468. {
  469.   // Signal für c2p4
  470.   c2p4_signal = AllocSignal(-1);
  471.   c2p4_set = 1 << c2p4_signal;
  472.  
  473.   // TimerIO einrichten
  474.   if (timer_port = CreateMsgPort()) {
  475.     if (timer_io = CreateIORequest(timer_port, sizeof(struct timerequest))) {
  476.       OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_io, 0);
  477.  
  478.       // timer_io für Speed Limiter starten
  479.       timer_io->tr_node.io_Command = TR_ADDREQUEST;
  480.       timer_io->tr_time.tv_secs = 0;
  481.       timer_io->tr_time.tv_micro = SkipLatch * 20000;  // 20ms pro Bild
  482.       SendIO((struct IORequest *)timer_io);
  483.     }
  484.   }
  485. }
  486.  
  487.  
  488. /*
  489.  *  Vom 6510-Task aus nötige Aufräumarbeiten
  490.  *  Wird vom 6510-Task aufgerufen
  491.  */
  492.  
  493. void ExitDisplayFrom6510(void)
  494. {
  495.   if (timer_io) {
  496.     if (!CheckIO((struct IORequest *)timer_io))
  497.       WaitIO((struct IORequest *)timer_io);
  498.     CloseDevice((struct IORequest *)timer_io);
  499.     DeleteIORequest((struct IORequest *)timer_io);
  500.     timer_io = NULL;
  501.   }
  502.  
  503.   if (timer_port) {
  504.     DeleteMsgPort(timer_port);
  505.     timer_port = NULL;
  506.   }
  507.  
  508.   // Ggf. auf Signal von c2p4 warten
  509.   if (must_wait_for_c2p4)
  510.     Wait(c2p4_set);
  511.  
  512.   FreeSignal(c2p4_signal);
  513. }
  514.  
  515.  
  516. /*
  517.  *  C64-Grafik neu darstellen (VBlank, Double Buffering)
  518.  *  Wird vom 6510-Task aufgerufen
  519.  */
  520.  
  521. struct timeval start_time, end_time;
  522. char speed_str[20];
  523. int percent;
  524.  
  525. void RedrawDisplay(void)
  526. {
  527.   switch (current_type) {
  528.     // SCRTYPE_8BIT: WritePixelLine in 6569.asm
  529.  
  530.     case SCRTYPE_4BIT:        // Double Buffering und c2p-Konvertierung
  531.       if (must_wait_for_c2p4)
  532.         Wait(c2p4_set);
  533.  
  534.       if (using_db) {
  535.         while (!ChangeScreenBuffer(the_screen, scr_buf[inv_buf_num]))
  536.           WaitTOF();
  537.         inv_buf_num ^= 1;
  538.         c2p4(ChunkyBuf, comparison_buf[inv_buf_num], scr_buf[inv_buf_num]->sb_BitMap->Planes, CPUTask, c2p4_set);
  539.       } else
  540.         c2p4(ChunkyBuf, comparison_buf[0], the_rast_port->BitMap->Planes, CPUTask, c2p4_set);
  541.  
  542.       must_wait_for_c2p4 = TRUE;
  543.       CURRENTA5 = ChunkyBuf;
  544.       break;
  545.  
  546.     case SCRTYPE_1BIT:        // Double Buffering
  547.       if (using_db) {
  548.         while (!ChangeScreenBuffer(the_screen, scr_buf[inv_buf_num]))
  549.           WaitTOF();
  550.         inv_buf_num ^= 1;
  551.         CURRENTA5 = scr_buf[inv_buf_num]->sb_BitMap->Planes[0];
  552.       } else
  553.         CURRENTA5 = the_rast_port->BitMap->Planes[0];
  554.       break;
  555.  
  556.     case SCRTYPE_GRAF:        // Chunky->ModeX
  557.       graffiti_conv(the_rast_port->BitMap->Planes[0]+80, the_rast_port->BitMap->Planes[1]+80,
  558.         the_rast_port->BitMap->Planes[2]+80, the_rast_port->BitMap->Planes[3]+80);
  559.       CURRENTA5 = ChunkyBuf;
  560.       break;
  561.   }
  562.  
  563.   if (timer_io) {
  564.     // timer_io abbrechen, wenn Speed Limiter aus ist
  565.     if (!LimitSpeed)
  566.       if (!CheckIO((struct IORequest *)timer_io))
  567.         AbortIO((struct IORequest *)timer_io);
  568.  
  569.     WaitIO((struct IORequest *)timer_io);
  570.  
  571.     // timer_io neu starten
  572.     timer_io->tr_node.io_Command = TR_ADDREQUEST;
  573.     timer_io->tr_time.tv_secs = 0;
  574.     timer_io->tr_time.tv_micro = SkipLatch * 20000;  // 20ms pro Bild
  575.     SendIO((struct IORequest *)timer_io);
  576.   }
  577.  
  578.   // Zeit seit letztem Aufruf ermitteln
  579.   GetSysTime(&end_time);
  580.   SubTime(&end_time, &start_time);
  581.   GetSysTime(&start_time);
  582.  
  583.   // Ein Bild sollte 20ms dauern
  584.   percent = (20000 * 100 / end_time.tv_micro + 1) * SkipLatch;
  585.  
  586.   if (current_type != SCRTYPE_GRAF) { // Auf Graffiti unleserlich
  587.     RawDoFmt("%ld%%", &percent, &PutChProc, speed_str);
  588.     Move(the_rast_port, 4, current_height-6);
  589.     Text(the_rast_port, speed_str, strlen(speed_str));
  590.   }
  591. }
  592.  
  593.  
  594. /*
  595.  *  C64-Grafik nach hinten
  596.  */
  597.  
  598. void EmulToBack(void)
  599. {
  600.   ScreenToBack(the_screen);
  601.   ModifyIDCMP(the_window, IDCMP_RAWKEY);
  602.   ClearMenuStrip(the_window);
  603. }
  604.  
  605.  
  606. /*
  607.  *  C64-Grafik nach vorne
  608.  */
  609.  
  610. void EmulToFront(void)
  611. {
  612.   ScreenToFront(the_screen);
  613.   ModifyIDCMP(the_window, IDCMP_RAWKEY | IDCMP_MENUPICK | IDCMP_MENUVERIFY);
  614.   SetMenuStrip(the_window, the_menus);
  615. }
  616.  
  617.  
  618. /*
  619.  *  Event-Schleife des Fensters
  620.  */
  621.  
  622. void EventLoop(void)
  623. {
  624.   int done = FALSE;
  625.   ULONG signals;
  626.  
  627.   while (!done) {
  628.     signals = Wait((1 << the_window->UserPort->mp_SigBit) | InvokeSAMSet);
  629.  
  630.     if (signals & (1 << the_window->UserPort->mp_SigBit))
  631.       done = handle_IDCMP(done);
  632.  
  633.     if (signals & InvokeSAMSet)
  634.       handle_menu(0, 1, done);
  635.   }
  636. }
  637.  
  638.  
  639. /*
  640.  *  IDCMP-Messages handhaben
  641.  */
  642.  
  643. int handle_IDCMP(int done)
  644. {
  645.   struct IntuiMessage *msg;
  646.   ULONG class;
  647.   UWORD code;
  648.   UWORD menu_number;
  649.   struct MenuItem *item;
  650.  
  651.   while (!done && (msg = GetMsg(the_window->UserPort))) {
  652.     class = msg->Class;
  653.     code = msg->Code;
  654.  
  655.     if (class == IDCMP_MENUVERIFY)
  656.       Pause6510();    // Subtask stoppen
  657.  
  658.     ReplyMsg((struct Message *)msg);
  659.  
  660.     switch (class) {
  661.       case IDCMP_MENUPICK:
  662.         Resume6510();  // Subtask fortführen
  663.  
  664.         if (current_type == SCRTYPE_GRAF)
  665.           set_graffiti_commands(); // Graffiti-Kommandos wurden durch Menü übermalt
  666.  
  667.         menu_number = code;
  668.         while (!done && (menu_number != MENUNULL)) {
  669.           item = ItemAddress(the_window->MenuStrip, menu_number);
  670.           done = handle_menu(MENUNUM(menu_number), ITEMNUM(menu_number), done);
  671.           menu_number = item->NextSelect;
  672.         }
  673.         break;
  674.  
  675.       case IDCMP_RAWKEY:
  676.         switch (code) {
  677.           case 0x59:    // F10: Reset
  678.             ResetC64();
  679.             break;
  680.           case 0x5f:    // Help: JoystickSwap umschalten
  681.             JoystickSwap = JoystickSwap ? 0 : -1;
  682.             break;
  683.           case 0x5e:    // + (NK): SkipLatch erhöhen
  684.             SkipLatch++;
  685.             break;
  686.           case 0x4a:    // - (NK): SkipLatch erniedrigen
  687.             if (SkipLatch > 1)
  688.               SkipLatch--;
  689.             break;
  690.           default:
  691.             KeyPressed(code);
  692.         }
  693.         break;
  694.     }
  695.   }
  696.  
  697.   return done;
  698. }
  699.  
  700.  
  701. /*
  702.  *  Menü wurde ausgewählt
  703.  */
  704.  
  705. int handle_menu(int menu, int item, int done)
  706. {
  707.   if (menu == 0) {
  708.     switch (item) {
  709.       case 0:        // Einstellungen
  710.         Pause6510();
  711.         PauseSound();
  712.         EmulToBack();
  713.         ShowPrefs();
  714.         EmulToFront();
  715.         ResumeSound();
  716.         Resume6510();
  717.         break;
  718.  
  719.       case 1:        // SAM
  720.         Pause6510();
  721.         PauseSound();
  722.         EmulToBack();
  723.         SAM();
  724.         EmulToFront();
  725.         ResumeSound();
  726.         Resume6510();
  727.         break;
  728.  
  729.       case 3:        // Quit
  730.         done = TRUE;
  731.         break;
  732.     }
  733.   }
  734.  
  735.   return done;
  736. }
  737.  
  738.  
  739. /*
  740.  *  Requester anzeigen
  741.  */
  742.  
  743. int ShowRequester(int text, int gads, APTR args)
  744. {
  745.   struct EasyStruct es;
  746.  
  747.   es.es_StructSize = sizeof(struct EasyStruct);
  748.   es.es_Flags = 0;
  749.   es.es_Title = GetStr(MSG_REQTITLE);
  750.   es.es_TextFormat = GetStr(text);
  751.   es.es_GadgetFormat = GetStr(gads);
  752.  
  753.   return EasyRequestArgs(NULL, &es, NULL, args);
  754. }
  755.  
  756.  
  757. /*
  758.  *  Lokalisierungen vornehmen
  759.  */
  760.  
  761. void LocalizeDisplay(void)
  762. {
  763.   int i;
  764.  
  765.   for (i=0; new_menus[i].nm_Type != NM_END; i++)
  766.     if (new_menus[i].nm_Label != NM_BARLABEL)
  767.       new_menus[i].nm_Label = GetStr((int)new_menus[i].nm_Label);
  768. }
  769.